﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CC98.Network.Primitives
{
    public class CC98HttpClientHandler : HttpClientHandler
    {
        public CC98HttpClientHandler(string username)
        {
            // Tell system to handle cookies
            this.UseCookies = true;
            this.CookieContainer = new CookieContainer();
            this.Username = username;
        }

        public CC98HttpClientHandler(Session session)
        {
            if (session == null)
                throw new ArgumentNullException("session");
            // Init
            this.UseCookies = true;
            this.CookieContainer = new CookieContainer();
            this.Username = session.Username;
            this.CookieContainer.Add(CookieUri, session.Cookies);
            // Validate session
            this.ValidateCookie(session.Cookies);
            if(this.IsAuthenticated)
                this.LoginTime = session.LoginTime;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
           return Task<HttpResponseMessage>.Factory.StartNew(new Func<HttpResponseMessage>(() =>
                {
                    var task = base.SendAsync(request, cancellationToken);
                    task.Wait();
                    if (task.IsCompleted)
                    {
                        this.ValidateResponse(task.Result);
                        return task.Result;
                    }
                    else
                    {
                        if (task.IsFaulted)
                            throw new InvalidOperationException(string.Empty, task.Exception);
                        return null;
                    }
                }));
        }

        public bool IsAuthenticated
        {
            get
            {
                return this._isAuthenticated;
            }
        }

        public int UserID { get; private set; }

        public string Username { get; private set; }

        public DateTime? LoginTime { get; private set; }

        public Session GetSession()
        {
            return new Session(this.Username, this.CookieContainer.GetCookies(CookieUri), this.LoginTime);
        }

        public void ResetHandler()
        {
            this.CookieContainer = new CookieContainer();
            this.LoginTime = null;
            this.OnAuthenticationStateChanged(false);
        }

        public event EventHandler<AuthenticationStateChangedEventArgs> AuthenticationStateChanged;

        protected virtual void ValidateResponse(HttpResponseMessage message)
        {
            // Check cookie state
            if (this.CookieContainer != null)
            {
                var cookies = this.CookieContainer.GetCookies(CookieUri);
                this.ValidateCookie(cookies);
            }
            // Check content
        }

        protected virtual void ValidateCookie(CookieCollection cookies)
        {
            if (cookies != null)
            {
                var authValue = cookies["aspsky"].Value;
                if (authValue != null)
                {
                    var param = UrlEncoding.Decode(authValue);
                    if (param.ContainsKey("username")
                        && param["username"] == this.Username
                        && param.ContainsKey("password")
                        && param.ContainsKey("userid"))
                    {
                        System.Diagnostics.Debug.WriteLine("[CC98HttpClientHandler][ValidateResponse]Authenticated for user" + this.Username);
                        this.UserID = int.Parse(param["userid"]);
                        if (!this.IsAuthenticated)
                            this.OnAuthenticationStateChanged(true);
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("[CC98HttpClientHandler][ValidateResponse]Not Authenticated for user" + this.Username);
                        if (this.IsAuthenticated)
                            this.OnAuthenticationStateChanged(false);
                    }
                }
            }
        }

        protected virtual void OnAuthenticationStateChanged(bool isAuthenticated)
        {
            this._isAuthenticated = isAuthenticated;

            if (IsAuthenticated)
                this.LoginTime = DateTime.Now;
            else
                this.LoginTime = null;

            if (this.AuthenticationStateChanged != null)
                this.AuthenticationStateChanged(this, new AuthenticationStateChangedEventArgs(isAuthenticated, this.Username));
        }

        private bool _isAuthenticated;

        private static readonly Uri CookieUri = new Uri("http://www.cc98.org/");
    }
}
